;;; functionality relevant for creating models
(defpackage model
  (:use :cl)
  (:nicknames :m)
  (:export :ensure-connection
           :dump-screen
           :close-connection
           :execute
           :no-connection
           :main-screen
           :list-sessions
           :list-options
           :start-session
           :disable-timers))

(defpackage :model-server
  (:use :cl)
  (:export :start
           :execute-action
           :dump-screen
           :main-screen
           :list-sessions
           :list-options
           :start-session
           :disable-timers))

(in-package :model)

(defvar *client* nil
  "The client used to send sexp's to the experiment.")

(defun ensure-connection ()
  (unless *client*
    (setf *client* (remote-eval:connect))))

(defun close-connection ()
  (when *client*
    (remote-eval:close-connection *client*)
    (setf *client* nil)
    t))

(defun clean-up-symbols (sexp)
  (cond
    ((keywordp sexp)
     sexp)
    ((and (symbolp sexp)
          (eq (symbol-package sexp) (find-package :cl)))
     sexp)
    ((symbolp sexp)
     (let ((sym (intern (symbol-name sexp) *package*)))
       sym))
    ((listp sexp)
     (mapcar 'clean-up-symbols sexp))
    (t
     sexp)))

(defmacro define-command (name args &optional (call `(quote ,(list (find-symbol (symbol-name name) :model-server)))))
  `(defun ,name ,args
     (ensure-connection)
     ;; make all the symbols appear to be in the current package
     (restart-case
         (values-list (mapcar 'clean-up-symbols
                              (multiple-value-list (remote-eval:eval ,call *client*))))
       (close-connection ()
         :report "Close Connection to Experiment."
         (close-connection)))))

(define-command dump-screen ())
(define-command execute (action-class &rest args &key &allow-other-keys)
  `(model-server:execute-action ',action-class ,@(mapcar (lambda (a) (list 'quote a)) args)))
(define-command main-screen ())
(define-command list-sessions (id)
  `(model-server:list-sessions ,id))
(define-command list-options ())
(define-command start-session (id session &rest options &key &allow-other-keys)
 `(model-server:start-session ,id ,session ,@options))
(define-command disable-timers ())